home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / glibc108.zip / glibc108 / stdio / vfprintf.c < prev    next >
C/C++ Source or Header  |  1994-05-23  |  14KB  |  675 lines

  1. /* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3.  
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of the
  7. License, or (at your option) any later version.
  8.  
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with the GNU C Library; see the file COPYING.LIB.  If
  16. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  17. Cambridge, MA 02139, USA.  */
  18.  
  19. #include <ansidecl.h>
  20. #include <localeinfo.h>
  21. #include <ctype.h>
  22. #include <errno.h>
  23. #include <float.h>
  24. #include <limits.h>
  25. #include <math.h>
  26. #include <stdarg.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <printf.h>
  31. #include <assert.h>
  32. #include "_itoa.h"
  33.  
  34.  
  35. /* If it's an unbuffered stream that we provided
  36.    temporary buffering for, remove that buffering.  */
  37. #define    RETURN(x)                                  \
  38.   do                                          \
  39.     {                                          \
  40.       done = (x);                                  \
  41.       goto do_return;                                  \
  42.     } while (0)
  43.  
  44. #define    outchar(x)                                  \
  45.   do                                          \
  46.     {                                          \
  47.       register CONST int outc = (x);                          \
  48.       if (putc(outc, s) == EOF)                              \
  49.     RETURN(-1);                                  \
  50.       else                                      \
  51.     ++done;                                      \
  52.     } while (0)
  53.  
  54. /* Cast the next arg, of type ARGTYPE, into CASTTYPE, and put it in VAR.  */
  55. #define    castarg(var, argtype, casttype) \
  56.   var = (casttype) va_arg(args, argtype)
  57. /* Get the next arg, of type TYPE, and put it in VAR.  */
  58. #define    nextarg(var, type)    castarg(var, type, type)
  59.  
  60. static printf_function printf_unknown;
  61.  
  62. extern printf_function **__printf_function_table;
  63.  
  64. #ifdef    __GNUC__
  65. #define    HAVE_LONGLONG
  66. #define    LONGLONG    long long
  67. #else
  68. #define    LONGLONG    long
  69. #endif
  70.  
  71.  
  72. int
  73. DEFUN(vfprintf, (s, format, args),
  74.       register FILE *s AND CONST char *format AND va_list args)
  75. {
  76.   /* Pointer into the format string.  */
  77.   register CONST char *f;
  78.  
  79.   /* Number of characters written.  */
  80.   register size_t done = 0;
  81.  
  82.   /* Nonzero we're providing buffering.  */
  83.   char our_buffer;
  84.   /* Temporary buffer for unbuffered streams.  */
  85.   char temporary_buffer[BUFSIZ];
  86.  
  87.   if (!__validfp(s) || !s->__mode.__write || format == NULL)
  88.     {
  89.       errno = EINVAL;
  90.       return -1;
  91.     }
  92.  
  93.   if (!s->__seen)
  94.     {
  95.       if (__flshfp(s, EOF) == EOF)
  96.     return EOF;
  97.     }
  98.  
  99.   our_buffer = s->__buffer == NULL;
  100.   if (our_buffer)
  101.     {
  102.       /* If it's an unbuffered stream, buffer it
  103.      at least inside this function call.  */
  104.       s->__bufp = s->__buffer = temporary_buffer;
  105.       s->__bufsize = sizeof(temporary_buffer);
  106.       s->__put_limit = s->__buffer + s->__bufsize;
  107.       s->__get_limit = s->__buffer;
  108.     }
  109.  
  110.   /* Reset multibyte characters to their initial state.  */
  111.   (void) mblen((char *) NULL, 0);
  112.  
  113.   f = format;
  114.   while (*f != '\0')
  115.     {
  116.       /* Type modifiers.  */
  117.       char is_short, is_long, is_long_double;
  118. #ifdef    HAVE_LONGLONG
  119.       /* We use the `L' modifier for `long long int'.  */
  120. #define    is_longlong    is_long_double
  121. #else
  122. #define    is_longlong    0
  123. #endif
  124.       /* Format spec modifiers.  */
  125.       char space, showsign, left, alt;
  126.  
  127.       /* Padding character: ' ' or '0'.  */
  128.       char pad;
  129.       /* Width of a field.  */
  130.       register int width;
  131.       /* Precision of a field.  */
  132.       int prec;
  133.  
  134.       /* Decimal integer is negative.  */
  135.       char is_neg;
  136.  
  137.       /* Current character of the format.  */
  138.       char fc;
  139.  
  140.       /* Base of a number to be written.  */
  141.       int base;
  142.       /* Integral values to be written.  */
  143.       unsigned LONGLONG int num;
  144.       LONGLONG int signed_num;
  145.  
  146.       /* String to be written.  */
  147.       CONST char *str;
  148.       char unknown_error[256];    /* Buffer sometimes used by %m.  */
  149.  
  150.       /* Auxiliary function to do output.  */
  151.       printf_function *function;
  152.  
  153.       if (!isascii(*f))
  154.     {
  155.       /* Non-ASCII, may be a multibyte.  */
  156.       int len = mblen(f, strlen(f));
  157.       if (len > 0)
  158.         {
  159.           while (len-- > 0)
  160.         outchar(*f++);
  161.           continue;
  162.         }
  163.     }
  164.  
  165.       if (*f != '%')
  166.     {
  167.       /* This isn't a format spec, so write
  168.          everything out until the next one.  */
  169.       CONST char *next = strchr(f + 1, '%');
  170.       if (next == NULL)
  171.         next = strchr(f + 1, '\0');
  172.       if (next - f > 20)
  173.         {
  174.           size_t written = fwrite((PTR) f, 1, next - f, s);
  175.           done += written;
  176.           if (written != next - f)
  177.         break;
  178.           f += written;
  179.         }
  180.       else
  181.         while (f < next)
  182.           outchar(*f++);
  183.       continue;
  184.     }
  185.  
  186.       ++f;
  187.  
  188.       /* Check for "%%".  Note that although the ANSI standard lists
  189.      '%' as a conversion specifier, it says "The complete format
  190.      specification shall be `%%'," so we can avoid all the width
  191.      and precision processing.  */
  192.       if (*f == '%')
  193.     {
  194.       ++f;
  195.       outchar('%');
  196.       continue;
  197.     }
  198.  
  199.       /* Check for spec modifiers.  */
  200.       space = showsign = left = alt = 0;
  201.       pad = ' ';
  202.       while (*f == ' ' || *f == '+' || *f == '-' || *f == '#' || *f == '0')
  203.     switch (*f++)
  204.       {
  205.       case ' ':
  206.         /* Output a space in place of a sign, when there is no sign.  */
  207.         space = 1;
  208.         break;
  209.       case '+':
  210.         /* Always output + or - for numbers.  */
  211.         showsign = 1;
  212.         break;
  213.       case '-':
  214.         /* Left-justify things.  */
  215.         left = 1;
  216.         break;
  217.       case '#':
  218.         /* Use the "alternate form":
  219.            Hex has 0x or 0X, FP always has a decimal point.  */
  220.         alt = 1;
  221.         break;
  222.       case '0':
  223.         /* Pad with 0s.  */
  224.         pad = '0';
  225.         break;
  226.       }
  227.       if (left)
  228.     pad = ' ';
  229.  
  230.       /* Get the field width.  */
  231.       width = 0;
  232.       if (*f == '*')
  233.     {
  234.       /* The field width is given in an argument.
  235.          A negative field width indicates left justification.  */
  236.       nextarg(width, int);
  237.       if (width < 0)
  238.         {
  239.           width = - width;
  240.           left = 1;
  241.         }
  242.       ++f;
  243.     }
  244.       else
  245.     while (isdigit(*f))
  246.       {
  247.         width *= 10;
  248.         width += *f++ - '0';
  249.       }
  250.  
  251.       /* Get the precision.  */
  252.       /* -1 means none given; 0 means explicit 0.  */
  253.       prec = -1;
  254.       if (*f == '.')
  255.     {
  256.       ++f;
  257.       if (*f == '*')
  258.         {
  259.           /* The precision is given in an argument.  */
  260.           nextarg(prec, int);
  261.           /* Avoid idiocy.  */
  262.           if (prec < 0)
  263.         prec = -1;
  264.           ++f;
  265.         }
  266.       else if (isdigit(*f))
  267.         {
  268.           prec = 0;
  269.           while (*f != '\0' && isdigit(*f))
  270.         {
  271.           prec *= 10;
  272.           prec += *f++ - '0';
  273.         }
  274.         }
  275.     }
  276.  
  277.       /* Check for type modifiers.  */
  278.       is_short = is_long = is_long_double = 0;
  279.       while (*f == 'h' || *f == 'l' || *f == 'L')
  280.     switch (*f++)
  281.       {
  282.       case 'h':
  283.         /* int's are short int's.  */
  284.         is_short = 1;
  285.         break;
  286.       case 'l':
  287. #ifdef    HAVE_LONGLONG
  288.         if (is_long)
  289.           /* A double `l' is equivalent to an `L'.  */
  290.           is_longlong = 1;
  291.         else
  292. #endif
  293.           /* int's are long int's.  */
  294.           is_long = 1;
  295.         break;
  296.       case 'L':
  297.         /* double's are long double's, and int's are long long int's.  */
  298.         is_long_double = 1;
  299.         break;
  300.  
  301.       case 'Z':
  302.         /* int's are size_t's.  */
  303. #ifdef    HAVE_LONGLONG
  304.         assert (sizeof(size_t) <= sizeof(unsigned long long int));
  305.         is_longlong = sizeof(size_t) > sizeof(unsigned long int);
  306. #endif
  307.         is_long = sizeof(size_t) > sizeof(unsigned int);
  308.         break;
  309.       }
  310.  
  311.       /* Format specification.  */
  312.       fc = *f++;
  313.       function = (__printf_function_table == NULL ? NULL :
  314.           __printf_function_table[fc]);
  315.       if (function == NULL)
  316.     switch (fc)
  317.       {
  318.       case 'i':
  319.       case 'd':
  320.         /* Decimal integer.  */
  321.         base = 10;
  322.         if (is_longlong)
  323.           nextarg(signed_num, LONGLONG int);
  324.         else if (is_long)
  325.           nextarg(signed_num, long int);
  326.         else if (!is_short)
  327.           castarg(signed_num, int, long int);
  328.         else
  329.           castarg(signed_num, int, short int);
  330.  
  331.         is_neg = signed_num < 0;
  332.         num = is_neg ? (- signed_num) : signed_num;
  333.         goto number;
  334.  
  335.       case 'u':
  336.         /* Decimal unsigned integer.  */
  337.         base = 10;
  338.         goto unsigned_number;
  339.  
  340.       case 'o':
  341.         /* Octal unsigned integer.  */
  342.         base = 8;
  343.         goto unsigned_number;
  344.  
  345.       case 'X':
  346.         /* Hexadecimal unsigned integer.  */
  347.       case 'x':
  348.         /* Hex with lower-case digits.  */
  349.  
  350.         base = 16;
  351.  
  352.       unsigned_number:
  353.         /* Unsigned number of base BASE.  */
  354.  
  355.         if (is_longlong)
  356.           castarg(num, LONGLONG int, unsigned LONGLONG int);
  357.         else if (is_long)
  358.           castarg(num, long int, unsigned long int);
  359.         else if (!is_short)
  360.           castarg(num, int, unsigned int);
  361.         else
  362.           castarg(num, int, unsigned short int);
  363.  
  364.         /* ANSI only specifies the `+' and
  365.            ` ' flags for signed conversions.  */
  366.         is_neg = showsign = space = 0;
  367.  
  368.       number:
  369.         /* Number of base BASE.  */
  370.         {
  371.           char work[BUFSIZ];
  372.           char *CONST workend = &work[sizeof(work) - 1];
  373.           register char *w;
  374.  
  375.           /* Supply a default precision if none was given.  */
  376.           if (prec == -1)
  377.         prec = 1;
  378.  
  379.           /* Put the number in WORK.  */
  380.           w = _itoa (num, workend + 1, base, fc == 'X') - 1;
  381.           width -= workend - w;
  382.           prec -= workend - w;
  383.  
  384.           if (alt && base == 8 && prec <= 0)
  385.         {
  386.           *w-- = '0';
  387.           --width;
  388.         }
  389.  
  390.           if (prec > 0)
  391.         {
  392.           width -= prec;
  393.           while (prec-- > 0)
  394.             *w-- = '0';
  395.         }
  396.  
  397.           if (alt && base == 16)
  398.         width -= 2;
  399.  
  400.           if (is_neg || showsign || space)
  401.         --width;
  402.  
  403.           if (!left && pad == ' ')
  404.         while (width-- > 0)
  405.           outchar(' ');
  406.  
  407.           if (is_neg)
  408.         outchar('-');
  409.           else if (showsign)
  410.         outchar('+');
  411.           else if (space)
  412.         outchar(' ');
  413.  
  414.           if (alt && base == 16)
  415.         {
  416.           outchar ('0');
  417.           outchar (fc);
  418.         }
  419.  
  420.           if (!left && pad == '0')
  421.         while (width-- > 0)
  422.           outchar('0');
  423.  
  424.           /* Write the number.  */
  425.           while (++w <= workend)
  426.         outchar(*w);
  427.  
  428.           if (left)
  429.         while (width-- > 0)
  430.           outchar(' ');
  431.         }
  432.         break;
  433.  
  434.       case 'e':
  435.       case 'E':
  436.       case 'f':
  437.       case 'g':
  438.       case 'G':
  439.         {
  440.           /* Floating-point number.  */
  441.           extern printf_function __printf_fp;
  442.           function = __printf_fp;
  443.           goto use_function;
  444.         }
  445.  
  446.       case 'c':
  447.         /* Character.  */
  448.         nextarg(num, int);
  449.         if (!left)
  450.           while (--width > 0)
  451.         outchar(' ');
  452.         outchar((unsigned char) num);
  453.         if (left)
  454.           while (--width > 0)
  455.         outchar(' ');
  456.         break;
  457.  
  458.       case 's':
  459.         {
  460.           static CONST char null[] = "(null)";
  461.           size_t len;
  462.  
  463.           nextarg(str, CONST char *);
  464.  
  465.         string:
  466.  
  467.           if (str == NULL)
  468.         /* Write "(null)" if there's space.  */
  469.         if (prec == -1 || prec >= (int) sizeof(null) - 1)
  470.           {
  471.             str = null;
  472.             len = sizeof(null) - 1;
  473.           }
  474.         else
  475.           {
  476.             str = "";
  477.             len = 0;
  478.           }
  479.           else
  480.         len = strlen(str);
  481.  
  482.           if (prec != -1 && (size_t) prec < len)
  483.         len = prec;
  484.           width -= len;
  485.  
  486.           if (!left)
  487.         while (width-- > 0)
  488.           outchar(' ');
  489.           if (len < 20)
  490.         while (len-- > 0)
  491.           outchar(*str++);
  492.           else
  493.         if (fwrite(str, 1, len, s) != len)
  494.           RETURN(-1);
  495.         else
  496.           done += len;
  497.           if (left)
  498.         while (width-- > 0)
  499.           outchar(' ');
  500.         }
  501.         break;
  502.  
  503.       case 'p':
  504.         /* Generic pointer.  */
  505.         {
  506.           CONST PTR ptr;
  507.           nextarg(ptr, CONST PTR);
  508.           if (ptr != NULL)
  509.         {
  510.           /* If the pointer is not NULL, write it as a %#x spec.  */
  511.           base = 16;
  512.           fc = 'x';
  513.           alt = 1;
  514.           num = (unsigned LONGLONG int) (unsigned long int) ptr;
  515.           is_neg = 0;
  516.           goto number;
  517.         }
  518.           else
  519.         {
  520.           /* Write "(nil)" for a nil pointer.  */
  521.           static CONST char nil[] = "(nil)";
  522.           register CONST char *p;
  523.  
  524.           width -= sizeof (nil) - 1;
  525.           if (!left)
  526.             while (width-- > 0)
  527.               outchar (' ');
  528.           for (p = nil; *p != '\0'; ++p)
  529.             outchar (*p);
  530.           if (left)
  531.             while (width-- > 0)
  532.               outchar (' ');
  533.         }
  534.         }
  535.         break;
  536.  
  537.       case 'n':
  538.         /* Answer the count of characters written.  */
  539.         if (is_longlong)
  540.           {
  541.         LONGLONG int *p;
  542.         nextarg(p, LONGLONG int *);
  543.         *p = done;
  544.           }
  545.         else if (is_long)
  546.           {
  547.         long int *p;
  548.         nextarg(p, long int *);
  549.         *p = done;
  550.           }
  551.         else if (!is_short)
  552.           {
  553.         int *p;
  554.         nextarg(p, int *);
  555.         *p = done;
  556.           }
  557.         else
  558.           {
  559.         short int *p;
  560.         nextarg(p, short int *);
  561.         *p = done;
  562.           }
  563.         break;
  564.  
  565.       case 'm':
  566. #ifndef HAVE_GNU_LD
  567. #define _sys_errlist sys_errlist
  568. #define _sys_nerr sys_nerr
  569. #endif
  570.  
  571.         if (errno < 0 || errno > _sys_nerr)
  572.           {
  573.         sprintf (unknown_error, "Unknown error %d", errno);
  574.         str = unknown_error;
  575.           }
  576.         else
  577.           str = _sys_errlist[errno];
  578.         goto string;
  579.  
  580.       default:
  581.         /* Unrecognized format specifier.  */
  582.         function = printf_unknown;
  583.         goto use_function;
  584.       }
  585.       else
  586.       use_function:
  587.     {
  588.       int function_done;
  589.       struct printf_info info;
  590.  
  591.       info.prec = prec;
  592.       info.width = width;
  593.       info.spec = fc;
  594.       info.is_long_double = is_long_double;
  595.       info.is_short = is_short;
  596.       info.is_long = is_long;
  597.       info.alt = alt;
  598.       info.space = space;
  599.       info.left = left;
  600.       info.showsign = showsign;
  601.       info.pad = pad;
  602.  
  603.       function_done = (*function)(s, &info, &args);
  604.       if (function_done < 0)
  605.         RETURN(-1);
  606.  
  607.       done += function_done;
  608.     }
  609.     }
  610.  
  611.  do_return:;
  612.   if (our_buffer)
  613.     {
  614.       if (fflush(s) == EOF)
  615.     return -1;
  616.       s->__buffer = s->__bufp = s->__get_limit = s->__put_limit = NULL;
  617.       s->__bufsize = 0;
  618.     }
  619.   return done;
  620. }
  621.  
  622.  
  623. #undef    RETURN
  624. #define    RETURN    return
  625.  
  626. static int
  627. DEFUN(printf_unknown, (s, type, info, arg),
  628.       FILE *s AND CONST struct printf_info *info AND va_list *arg)
  629. {
  630.   int done = 0;
  631.   char work[BUFSIZ];
  632.   char *CONST workend = &work[sizeof(work) - 1];
  633.   register char *w;
  634.   register int prec = info->prec, width = info->width;
  635.  
  636.   outchar('%');
  637.  
  638.   if (info->alt)
  639.     outchar('#');
  640.   if (info->showsign)
  641.     outchar('+');
  642.   else if (info->space)
  643.     outchar(' ');
  644.   if (info->left)
  645.     outchar('-');
  646.   if (info->pad == '0')
  647.     outchar('0');
  648.  
  649.   w = workend;
  650.   while (width > 0)
  651.     {
  652.       *w-- = '0' + (width % 10);
  653.       width /= 10;
  654.     }
  655.   while (++w <= workend)
  656.     outchar(*w);
  657.  
  658.   if (info->prec != -1)
  659.     {
  660.       outchar('.');
  661.       w = workend;
  662.       while (prec > 0)
  663.     {
  664.       *w-- = '0' + (prec % 10);
  665.       prec /= 10;
  666.     }
  667.       while (++w <= workend)
  668.     outchar(*w);
  669.     }
  670.  
  671.   outchar(info->spec);
  672.  
  673.   return done;
  674. }
  675.